﻿using Sustainalytics.LongRunningTaskManager.Interface;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Sustainalytics.LongRunningTaskManager
{
    /// <summary>
    /// Task instance async info containing information related to async execution.
    /// </summary>
    public class LongRunningTaskInstanceAsyncInfo : ILongRunningTaskInstanceAsyncInfo
    {
        // event handles used to notify 
        private readonly ManualResetEvent _mreScheduled = new ManualResetEvent(false);
        private readonly ManualResetEvent _mreRunning = new ManualResetEvent(false);
        private readonly ManualResetEvent _mreFinished = new ManualResetEvent(false);
        private readonly ManualResetEvent _mreFailed = new ManualResetEvent(false);
        private readonly ManualResetEvent _mreCancelled = new ManualResetEvent(false);

        /// <summary>
        /// Task managed task.
        /// </summary>
        public Task<ILongRunningTaskResult> ManagedTask { get; private set; }

        /// <summary>
        /// Cancellation token used to cancel associated task.
        /// </summary>
        public CancellationToken TaskCancellationToken { get; private set; }


        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="managedTask"> Task managed task. </param>
        /// <param name="taskCancellationToken"> Cancellation token used to cancel the task. </param>
        public LongRunningTaskInstanceAsyncInfo(
            Task<ILongRunningTaskResult> managedTask,
            CancellationToken taskCancellationToken)
        {
            this.ManagedTask = managedTask;
            this.TaskCancellationToken = taskCancellationToken;
        }


        /// <summary>
        /// Set task status.
        /// </summary>
        /// <param name="taskStatus"> Task status. </param>
        internal void SetTaskStatus(LongRunningTaskInstanceStatusEnum taskStatus)
        {
            switch (taskStatus)
            {
                case LongRunningTaskInstanceStatusEnum.Scheduled:
                    _mreScheduled.Set();
                    break;
                case LongRunningTaskInstanceStatusEnum.Running:
                    _mreRunning.Set();
                    break;
                case LongRunningTaskInstanceStatusEnum.Finished:
                    _mreFinished.Set();
                    break;
                case LongRunningTaskInstanceStatusEnum.Failed:
                    _mreFailed.Set();
                    break;
                case LongRunningTaskInstanceStatusEnum.Cancelled:
                    _mreCancelled.Set();
                    break;
            }
        }

        /// <summary>
        /// Wait for status.
        /// </summary>
        /// <param name="taskStatus"> Task status to wait for. </param>
        public void WaitForStatus(LongRunningTaskInstanceStatusEnum taskStatus)
        {
            ManualResetEvent waitHandle = GetWaitHandle(taskStatus);
            waitHandle.WaitOne();
        }

        /// <summary>
        /// Wait for status.
        /// </summary>
        /// <param name="taskStatus"> Task status to wait for. </param>
        /// <param name="timeout"> Timeout to wait for. </param>
        public void WaitForStatus(LongRunningTaskInstanceStatusEnum taskStatus, TimeSpan timeout)
        {
            ManualResetEvent waitHandle = GetWaitHandle(taskStatus);
            waitHandle.WaitOne(timeout);
        }

        /// <summary>
        /// Wait for status.
        /// </summary>
        /// <param name="taskStatus"> Task status to wait for. </param>
        /// <param name="millisecondsTimeout"> Ms. to wait. </param>
        public void WaitForStatus(LongRunningTaskInstanceStatusEnum taskStatus, int millisecondsTimeout)
        {
            ManualResetEvent waitHandle = GetWaitHandle(taskStatus);
            waitHandle.WaitOne(millisecondsTimeout);
        }

        private ManualResetEvent GetWaitHandle(LongRunningTaskInstanceStatusEnum taskStatus)
        {
            switch (taskStatus)
            {
                case LongRunningTaskInstanceStatusEnum.Scheduled:
                    return _mreScheduled;
                case LongRunningTaskInstanceStatusEnum.Running:
                    return _mreRunning;
                case LongRunningTaskInstanceStatusEnum.Finished:
                    return _mreFinished;
                case LongRunningTaskInstanceStatusEnum.Failed:
                    return _mreFailed;
                case LongRunningTaskInstanceStatusEnum.Cancelled:
                    return _mreCancelled;
                default:
                    throw new NotSupportedException("Task status is not supported. Task status: " + taskStatus.ToString());
            }
        }
    }
}
